package com.wuji.salary.controller;

import com.wuji.salary.dao.AlgorithmDao;
import com.wuji.salary.entity.Info;
import com.wuji.salary.entity.R;
import com.wuji.salary.entity.Salary;
import com.wuji.salary.entity.SalaryDTO;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * 算薪逻辑
 */
@RestController
public class CalculatorController4 {

    @Resource
    private AlgorithmDao algorithmDao;

    @PostMapping("/CustomizedSalary4")
    public R calculateCustomizedSalary(@RequestBody Info info) {
        List<Salary> salaries = info.getSalaryList();
        ArrayList<SalaryDTO> list = new ArrayList<>();
        for (Salary salary : salaries) {
            //根据算法名从数据库去查询算法
            String formula = algorithmDao.getPayrollAlgorithmByName(salary.getPayrollAlgorithm());
            if (formula != null){
                // 预处理公式，添加空格
                formula = preprocessFormula(formula);

                // 使用两个栈分别存储操作符和操作数
                Stack<String> operatorStack = new Stack<>();
                Stack<Double> operandStack = new Stack<>();

                String[] elements = formula.split(" ");
                for (String element : elements) {
                    if (element.equals("(")) {
                        // 遇到左括号，将其入栈
                        operatorStack.push(element);
                    } else if (element.equals(")")) {
                        // 遇到右括号，计算括号内的表达式
                        while (!operatorStack.peek().equals("(")) {
                            performOperation(operatorStack.pop(), operandStack);
                        }
                        operatorStack.pop();  // 弹出左括号
                    } else if (isOperator(element)) {
                        // 处理普通操作符
                        while (!operatorStack.isEmpty() && hasHigherPrecedence(operatorStack.peek(), element) && !operatorStack.peek().equals("(")) {
                            performOperation(operatorStack.pop(), operandStack);
                        }
                        operatorStack.push(element);
                    } else {
                        // 动态获取参数值
                        try {
                            if (!element.isEmpty()) {
                                // 如果是数字，直接入栈
                                if (isNumeric(element)) {
                                    operandStack.push(Double.parseDouble(element));
                                    continue;
                                }

                                // 否则，通过反射获取属性值
                                Method getterMethod = Salary.class.getMethod("get" + element.substring(0, 1).toUpperCase() + element.substring(1));
                                Object value = getterMethod.invoke(salary);
                                if (value != null){
                                    operandStack.push(Double.parseDouble(value.toString()));
                                }else {
                                    return R.fail(element + " 该参数没有传值");
                                }
                            }
                        } catch (NoSuchMethodException e) {
                            System.err.println("未找到对应的获取方法: " + element);
                            R.fail(element+"该参数不存在");
                        } catch (IllegalAccessException e) {
                            System.err.println("非法访问异常: " + element);
                        } catch (InvocationTargetException e) {
                            System.err.println("调用目标异常: " + element);
                        }
                    }
                }

                // 处理剩余的操作符
                while (!operatorStack.isEmpty()) {
                    performOperation(operatorStack.pop(), operandStack);
                }

                // 属性赋值
                SalaryDTO salaryDTO = new SalaryDTO();
                salaryDTO.setQsName(salary.getQsName());
                salaryDTO.setJobNumber(salary.getJobNumber());
                salaryDTO.setStatisticalMonth(salary.getStatisticalMonth());
                salaryDTO.setQsSalary(BigDecimal.valueOf(operandStack.pop()));
                list.add(salaryDTO);
            }else {
                return R.fail("算法不存在");
            }
        }
        return R.ok(list);
    }

    // 预处理公式，添加空格
    private String preprocessFormula(String formula) {
        StringBuilder processedFormula = new StringBuilder();
        for (char c : formula.toCharArray()) {
            if (isOperator(c) || c == '(' || c == ')') {
                processedFormula.append(" ").append(c).append(" ");
            } else {
                processedFormula.append(c);
            }
        }
        return processedFormula.toString().trim();
    }

    // 判断是否为操作符
    private boolean isOperator(String element) {
        return element.equals("+") || element.equals("-") || element.equals("*") || element.equals("/");
    }

    // 判断是否为操作符（字符形式）
    private boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    // 判断操作符的优先级
    private boolean hasHigherPrecedence(String op1, String op2) {
        return (op1.equals("*") || op1.equals("/")) && (op2.equals("+") || op2.equals("-")) || op1.equals("(");
    }

    //执行计算操作
    private String performOperation(String operator, Stack<Double> operandStack) {
        double operand2 = operandStack.pop();
        double operand1 = operandStack.pop();

        double result = 0;
        switch (operator) {
            case "+":
                result = operand1 + operand2;
                break;
            case "-":
                // 如果栈顶元素（operand2）为负数，则将减法转换为加法
                if (operand1 < 0) {
                    operand2 = -operand2;
                    operator = "+";
                }
                result = operand1 - operand2;
                break;
            case "*":
                result = operand1 * operand2;
                break;
            case "/":
                result = operand2 == 0 ? 0 : operand1 / operand2;
                break;
        }
        operandStack.push(result);
        return null;
    }


    // 判断是否为数字
    private boolean isNumeric(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }
}
